package EmailService;

import Database.DBService;
import Extra.Analysis;
import com.sun.mail.imap.IMAPFolder;

import com.sun.mail.imap.IMAPStore;

import javax.mail.*;
import javax.mail.internet.InternetAddress;
import javax.mail.internet.MimeMessage;
import javax.mail.internet.MimeMultipart;
import javax.mail.internet.MimeUtility;
import java.io.IOException;

import java.io.UnsupportedEncodingException;
import java.util.*;



/**
 * 邮件接收类
 * @author Senze.Zheng
 */
public class MailReceiver {


    public static void receiveMail(ReceiveInfo info)throws Exception{

        // 判断是否需要身份验证
        MyAuthenticator authenticator = null;
        // 配置邮件信息的环境属性
        Properties props = info.getProperties();
        if(info.isValidate()){
            authenticator = new MyAuthenticator(info.getUserName(),
                                                info.getUserPassword());
        }

        Session session = Session.getInstance(props,authenticator);
        //session.setDebug(true);// 打印调试信息

        /**
         * 对应于Transport类
         * Store类实现特定邮件协议上的读、写、监视、查找等操作
         * 通过Javax.mail.Store类可以访问Folder类
         * 使用IMAP会话机制连接服务器，也可用POP3
         */
        IMAPStore store = (IMAPStore) session.getStore("imap");
        store.connect();

        /**
         * Folder类用于分级组织邮件，并提供照Message格式访问email的能力
         */
        IMAPFolder folder = (IMAPFolder)store.getFolder("INBOX");// 收件箱
        folder.open(Folder.READ_ONLY);// 以只读的方式

        // 邮箱中的信件总数
        int numOfTotal = folder.getMessageCount();
        // 邮箱中的未读信件总数
        int numOfUnread = folder.getUnreadMessageCount();
        // 邮箱中的新信件总数
        int numOfNew = folder.getNewMessageCount();
        System.out.println("共有"+ numOfTotal +"封邮件");
        System.out.println("共有"+ numOfNew +"封新邮件");
        System.out.println("共有"+ numOfUnread +"封未读邮件");

        // 获得收件箱的邮件列表
        Message[] messages = folder.getMessages();

        // 解析邮件
        readMessage(messages);

        folder.close(false);
        store.close();

    }

    /**
     * 解析邮件
     * @param messages 要解析的邮件列表
     * @throws MessagingException
     * @throws UnsupportedEncodingException
     */
    private static void readMessage(Message[] messages) throws MessagingException,IOException{

        if(messages == null || messages.length<1){
            throw new MessagingException("异常：未找到要解析的邮件！");
        }
        for(int i = 0;i<messages.length;i++) {
            MimeMessage msg = (MimeMessage) messages[i];
            System.out.println("------------------解析第" + msg.getMessageNumber() + "封邮件-------------------- ");
            System.out.println("主题: " + MimeUtility.decodeText(msg.getSubject()));
            System.out.println("发件人: " + getFrom(msg));
            System.out.println("收件人：" + getReceiveAddress(msg, null));
            System.out.println("发送时间：" + msg.getSentDate());
            boolean isContainerAttachment = isContainAttachment(msg);
            System.out.println("是否包含附件：" + isContainerAttachment);
            StringBuffer content = new StringBuffer(30);
            getMailTextContent(msg,content);
            System.out.println("邮件正文：" + (content.length()>100?content.substring(0,100) + "..." : content));
            // 语义分析
            InternetAddress address = (InternetAddress) msg.getFrom()[0];
            String name = DBService.getNameByEmail(address.getAddress());
            Analysis.ResultCode resultCode = Analysis.analysis(content.toString());
            if(resultCode == Analysis.ResultCode.Affirmative){
                System.out.println("语义分析结果：" + name + " likes me");
            }else if(resultCode == Analysis.ResultCode.Negative){
                System.out.println("语义分析结果：" + name + " doesn'Test like me");
            }else {
                System.out.println("语义分析结果：" + "I'm not sure if " + name + " like me");
            }
            System.out.println("------------------第" + msg.getMessageNumber() + "封邮件解析结束-------------------- ");
        }

    }

    /**
     * 获得邮件发件地址和发件人
     * @param msg 邮件内容
     * @return 姓名 <Email地址>
     * @throws MessagingException
     * @throws UnsupportedEncodingException
     */
    private static String getFrom(MimeMessage msg) throws MessagingException,UnsupportedEncodingException{

        String from = "";
        Address[] froms = msg.getFrom();
        if(froms.length<1){
            throw new MessagingException("异常：发件地址为空！");
        }
        InternetAddress address = (InternetAddress)froms[0];
        String person = address.getPersonal();
        if(person != null){
            person = MimeUtility.decodeText(person) + " ";
        }else{
            person = "";
        }
        from = person + "<" + address.getAddress() + ">";
        return from;

    }

    /**
     * 根据收件人类型获得收件人信息
     * @param msg 邮件内容
     * @param type 收件人类型
     * @return 收件人1<邮件地址1>，收件人2<邮件地址2>
     * @throws MessagingException
     */
    private static String getReceiveAddress(MimeMessage msg,Message.RecipientType type) throws MessagingException{

        StringBuffer receiveAddress = new StringBuffer();
        Address[] addresses = null;
        if(type == null){
            addresses = msg.getAllRecipients();
        }else{
            addresses = msg.getRecipients(type);
        }

        if(addresses == null || addresses.length<1){
            throw new MessagingException("异常：没有收件地址！");
        }
        for(Address address : addresses){
            InternetAddress internetAddress = (InternetAddress)address;
            receiveAddress.append(internetAddress.toUnicodeString()).append(",");
        }
        receiveAddress.deleteCharAt(receiveAddress.length()-1);// 删除最后一个逗号

        return receiveAddress.toString();

    }

    /**
     * 判断邮件中是否有附件
     * @param part 邮件内容
     * @return 存在返回true，否则返回false
     * @throws MessagingException
     * @throws IOException
     */
    private static boolean isContainAttachment(Part part) throws MessagingException,IOException {

        boolean flag = false;
        if(part.isMimeType("Multipart/*")){
            MimeMultipart multipart = (MimeMultipart)part.getContent();
            int partCount = multipart.getCount();
            for(int i = 0;i<partCount;i++){
                BodyPart bodyPart = multipart.getBodyPart(i);
                String disp = bodyPart.getDisposition();
                if(disp != null && (disp.equalsIgnoreCase(Part.ATTACHMENT)||disp.equalsIgnoreCase(Part.INLINE))){
                    flag = true;
                }else if(bodyPart.isMimeType("Multipart/*")){
                    flag = isContainAttachment(bodyPart);
                }else{
                    String contentType = bodyPart.getContentType();
                    if(contentType.indexOf("application")!=-1){
                        flag = true;
                    }
                    if(contentType.indexOf("name")!=-1){
                        flag = true;
                    }
                }
                if(flag)break;
            }
        }else if(part.isMimeType("message/rfc822")){
            flag = isContainAttachment((Part)part.getContent());
        }
        return flag;

    }

    /**
     * 获得邮件文本内容
     * @param part 邮件体
     * @param content 存储邮件文本内容的字符串
     * @throws MessagingException
     * @throws IOException
     */
    private static void getMailTextContent(Part part,StringBuffer content) throws MessagingException,IOException{

        boolean isContainTextAttach = part.getContentType().indexOf("name")>0;
        if(part.isMimeType("text/*")&&!isContainTextAttach){
            content.append(part.getContent().toString());
        }else if(part.isMimeType("message/rfc822")){
            getMailTextContent((Part)part.getContent(),content);
        }else if(part.isMimeType("multipart/*")){
            Multipart multipart = (Multipart)part.getContent();
            int partCount = multipart.getCount();
            for(int i =0;i<partCount;i++){
                BodyPart bodyPart = multipart.getBodyPart(i);
                getMailTextContent(bodyPart,content);
            }
        }

    }

}
